using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace ICP_MS.Plugin.Tune;

public class CheckExperiment
{
	public List<IsotopeRatio> Ratios = new List<IsotopeRatio>();

	public List<AnalyteIsotope> Isotopes = new List<AnalyteIsotope>();

	public List<AnalyseInfos> AnalyseResults = new List<AnalyseInfos>();

	public List<RatioResults> RatiosResults = new List<RatioResults>();

	public List<RatioStatistics> ratioStatistics = new List<RatioStatistics>();

	public List<StatisticResults> statisticResults = new List<StatisticResults>();

	public MassCalibration msc = new MassCalibration();

	public int sweeps = 10;

	public int dwelltime = 100;

	private Thread threadScan = null;

	private AutoResetEvent scanEvent = new AutoResetEvent(initialState: false);

	private List<double> massX = new List<double>();

	public bool bStableFunEnd = false;

	public bool TuneSucceed = false;

	private volatile bool bStable = false;

	public bool isRun { get; set; }

	public event EventHandler EventTuneFinish;

	public event EventHandler<MsgEventArgs> EventTuneMsg;

	public void InitIsotopes()
	{
		Isotopes.Clear();
		Isotopes.Clear();
		Ratios.Clear();
		InitIsotope("7Li");
		InitIsotope("9Be");
		InitIsotope("59Co");
		InitIsotope("89Y");
		InitIsotope("115In");
		InitIsotope("140Ce");
		InitIsotope("209Bi");
		InitIsotope("205Tl");
		InitIsotope("156Ce O");
		InitIsotope("140Ce++");
		InitIsotope("5Bkg");
		InitIsotope("101Bkg");
		InitIsotope("220Bkg");
		Isotopes = Isotopes.OrderBy((AnalyteIsotope r) => r.intMass).ToList();
		InitRatios(Isotopes.Find((AnalyteIsotope r) => r.symbol == "156Ce O"), Isotopes.Find((AnalyteIsotope r) => r.symbol == "140Ce"));
		InitRatios(Isotopes.Find((AnalyteIsotope r) => r.symbol == "140Ce++"), Isotopes.Find((AnalyteIsotope r) => r.symbol == "140Ce"));
	}

	private void InitIsotope(string symbol)
	{
		IList<AnalyteIsotope> isos1 = DataBase.Instance.GetAnalyteIsotopesBySymbol(symbol);
		if (isos1.Count > 0)
		{
			AnalyteIsotope selectIsotope = isos1.First();
			Isotopes.Add(selectIsotope);
		}
	}

	public void InitRatios(AnalyteIsotope isos1, AnalyteIsotope isos2)
	{
		if (isos1 != null && isos2 != null)
		{
			IsotopeRatio ratio = new IsotopeRatio
			{
				NumeratorId = isos1.id,
				NumeratorSym = isos1.symbol,
				DenominatorId = isos2.id,
				DenominatorSym = isos2.symbol,
				Name = isos1.symbol + "/" + isos2.symbol
			};
			Ratios.Add(ratio);
		}
	}

	public void StartScan()
	{
		Detector.finishReceive += Detector_finishReceive;
		isRun = true;
		threadScan = new Thread(ThreadScan);
		threadScan.Start();
	}

	public void StartMassScan()
	{
		Detector.finishReceive += Detector_finishReceive;
		isRun = true;
		ThreadMassScan();
	}

	private void ThreadMassScan()
	{
		InitMassFactors();
		msc.StartCheck();
	}

	private void InitMassFactors()
	{
		foreach (AnalyteIsotope isotope in Isotopes)
		{
			if (!(isotope.symbol == "156Ce O") && !(isotope.symbol == "140Ce++") && !(isotope.symbol == "5Bkg") && !(isotope.symbol == "101Bkg") && !(isotope.symbol == "220Bkg"))
			{
				MassFactor factor = new MassFactor();
				factor.kDC = 1.0;
				factor.kRF = 1.0;
				factor.isotopeId = isotope.id;
				factor.symbol = isotope.symbol;
				factor.mass = isotope.mass;
				factor.start = factor.mass - 1.0;
				factor.end = factor.mass + 1.0;
				factor.run = true;
				msc.MassFactors.Add(factor);
			}
		}
	}

	private void ThreadScan()
	{
		bStable = true;
		bool stableFunStop = false;
		Task.Factory.StartNew(delegate
		{
			while (bStable)
			{
				List<double> list = new List<double>();
				foreach (AnalyteIsotope current in Isotopes)
				{
					list.Add(current.mass);
				}
				List<int> list2 = new List<int>();
				for (int n = 0; n < list.Count; n++)
				{
					list2.Add(1);
				}
				Detector.Instance.SetMassAxis(list.ToArray());
				Detector.Instance.SendHopDatas(list.ToArray(), list2.ToArray(), true, false);
				if (!scanEvent.WaitOne(10000))
				{
					isRun = false;
					bStable = false;
					TuneMsg(Lang.Txt("CheckExperiment.Text1"));
					TuneFinish(success: false);
				}
				Thread.Sleep(5);
			}
			stableFunStop = true;
		});
		int stabletime = 40;
		int lefttime = stabletime;
		while (isRun && lefttime-- > 0)
		{
			TuneMsg(string.Format("1:" + Lang.Txt("FormExperiment.Status.Delay.Text") + "{0}s", lefttime));
			Thread.Sleep(1000);
		}
		bStable = false;
		int WaitTime = 60;
		while (!stableFunStop && isRun && WaitTime-- > 0)
		{
			Thread.Sleep(1000);
			TuneMsg(Lang.Txt("CheckExperiment.Text2"));
		}
		if (WaitTime <= 0)
		{
			Log.InsertLog(Lang.Txt("CheckExperiment.Text3"), Lang.Txt("CheckExperiment.Text4"), Detector.finishEvent(), (Severity)3);
			isRun = false;
		}
		if (!isRun)
		{
			return;
		}
		Thread.Sleep(1000);
		scanEvent.Reset();
		massX.Clear();
		foreach (AnalyteIsotope isotope2 in Isotopes)
		{
			massX.Add(isotope2.mass);
		}
		List<int> res = new List<int>();
		for (int k = 0; k < massX.Count; k++)
		{
			res.Add(1);
		}
		RFManager.rfs.dwell = dwelltime;
		Detector.Instance.msDetectorRF.SetDwell();
		AnalyseResults.Clear();
		RatiosResults.Clear();
		statisticResults.Clear();
		ratioStatistics.Clear();
		for (int m = 0; m < 3; m++)
		{
			for (int j = 0; j < sweeps; j++)
			{
				if (j == 0)
				{
					Detector.Instance.SetMassAxis(massX.ToArray());
				}
				Detector.Instance.SendHopDatas(massX.ToArray(), res.ToArray(), true, false);
				scanEvent.Reset();
				if (!scanEvent.WaitOne(60000))
				{
					TuneMsg(Lang.Txt("CheckExperiment.Text5"));
					TuneFinish(success: false);
					return;
				}
				TuneMsg(string.Format(Lang.Txt("CheckExperiment.Text6") + "{0}" + Lang.Txt("CheckExperiment.Text7") + "{1}" + Lang.Txt("AddFormSpectrums.Time"), m + 1, j + 1));
			}
			List<double> mass = Detector.msDetectorPara.MassAxis;
			double[] intensity = Detector.msDetectorPara.IntesnsityPulse;
			for (int i = 0; i < mass.Count(); i++)
			{
				int index = Isotopes.FindIndex((AnalyteIsotope r) => r.mass == mass[i]);
				if (index != -1 && AnalyseResults.FindIndex((AnalyseInfos r) => r.number == m && r.symbol == Isotopes[index].symbol) == -1)
				{
					AnalyseInfos analyseInfos = new AnalyseInfos
					{
						number = m,
						symbol = Isotopes[index].symbol,
						intensity = intensity[index] / (double)sweeps
					};
					AnalyseResults.Add(analyseInfos);
					TuneMsg(string.Format(Lang.Txt("CheckExperiment.Text8"), m + 1, analyseInfos.symbol, analyseInfos.intensity));
				}
			}
		}
		foreach (AnalyteIsotope isotope in Isotopes)
		{
			StatisticResults statistic = new StatisticResults();
			statistic.symbol = isotope.symbol;
			IEnumerable<double> resultlist = from result in AnalyseResults
				where result.symbol == isotope.symbol
				select result.intensity;
			statistic.avgCPS = CalculateAverage(resultlist.ToArray());
			statistic.sdCPS = CalculateDeviation(resultlist.ToArray());
			statistic.rsdCPS = statistic.sdCPS / statistic.avgCPS * 100.0;
			statisticResults.Add(statistic);
		}
		foreach (IsotopeRatio ratio in Ratios)
		{
			int l;
			for (l = 0; l < 10; l++)
			{
				RatioResults ratioResults = new RatioResults();
				IEnumerable<double> numerator = from cps in AnalyseResults
					where cps.symbol == ratio.NumeratorSym && cps.number == l
					select cps.intensity;
				IEnumerable<double> denominator = from cps in AnalyseResults
					where cps.symbol == ratio.DenominatorSym && cps.number == l
					select cps.intensity;
				if (numerator.Count() > 0 && denominator.Count() > 0)
				{
					ratioResults.Result = numerator.First() / denominator.First();
					ratioResults.Name = ratio.Name;
					RatiosResults.Add(ratioResults);
				}
			}
			IEnumerable<double> results = from result in RatiosResults
				where result.Name == ratio.Name
				select result.Result;
			if (results.Count() > 0)
			{
				RatioStatistics ratiostatistic = new RatioStatistics();
				ratiostatistic.Name = ratio.Name;
				ratiostatistic.Avg = CalculateAverage(results.ToArray());
				ratiostatistic.Sd = CalculateDeviation(results.ToArray());
				ratiostatistic.Rsd = ratiostatistic.Sd / ratiostatistic.Avg * 100.0;
				ratioStatistics.Add(ratiostatistic);
			}
		}
		TuneFinish(success: true);
	}

	private double CalculateAverage(double[] values)
	{
		if (values != null && values.Length != 0)
		{
			return values.Average();
		}
		return double.NaN;
	}

	private double CalculateDeviation(double[] values)
	{
		if (values == null)
		{
			return double.NaN;
		}
		double sum = 0.0;
		double sum2 = 0.0;
		int counter = 0;
		foreach (double val in values)
		{
			if (!double.IsNaN(val))
			{
				sum += val;
				sum2 += val * val;
				counter++;
			}
		}
		if (counter < 2)
		{
			return double.NaN;
		}
		return Math.Sqrt(((double)counter * sum2 - sum * sum) / (double)counter / (double)(counter - 1));
	}

	private void TuneFinish(bool success)
	{
		Detector.finishReceive -= Detector_finishReceive;
		TuneSucceed = success;
		if (this.EventTuneFinish != null)
		{
			this.EventTuneFinish(null, null);
		}
	}

	private void TuneMsg(string msg)
	{
		if (this.EventTuneMsg != null)
		{
			this.EventTuneMsg(null, new MsgEventArgs(msg));
		}
	}

	public void StopTune()
	{
		isRun = false;
		Detector.finishReceive -= Detector_finishReceive;
		if (threadScan != null && threadScan.IsAlive)
		{
			threadScan.Abort();
		}
		Detector.Instance.Stop();
		Detector.Instance.ExperimentState = -1;
	}

	private void Detector_finishReceive(object sender, EventArgs e)
	{
		scanEvent.Set();
	}

	public void ExperimentForStable()
	{
		Task.Factory.StartNew(delegate
		{
			bStableFunEnd = false;
			while (bStable)
			{
				List<double> list = new List<double>();
				foreach (AnalyteIsotope current in Isotopes)
				{
					list.Add(current.mass);
				}
				List<int> list2 = new List<int>();
				for (int i = 0; i < list.Count; i++)
				{
					list2.Add(1);
				}
				Detector.Instance.SetMassAxis(list.ToArray());
				Detector.Instance.SendHopDatas(list.ToArray(), list2.ToArray(), true, false);
				if (!scanEvent.WaitOne(10000))
				{
					isRun = false;
					bStable = false;
					TuneMsg(Lang.Txt("CheckExperiment.Text9"));
					TuneFinish(success: false);
				}
			}
			bStableFunEnd = true;
		});
	}
}
